package com.cn.tous.auth.controller;

import com.cn.tous.auth.config.processor.Oauth2Processor;
import com.cn.tous.auth.dtos.LoginParam;
import com.cn.tous.auth.dtos.TokenResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.time.Instant;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mengwei
 * @description AuthController
 * @createDate 2025/7/26 14:16
 */
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthenticationManager authenticationManager;

    private final RestTemplate restTemplate;

    // 从配置文件读取
    @Value("${server.port}")
    private int serverPort;
    @Value("${server.servlet.context-path}")
    private String contextPath;

    private final Oauth2Processor oauth2Processor;

    // 认证服务器的令牌端点（自己的服务地址）
    private String getTokenEndpoint() {
        return "http://localhost:" + serverPort + contextPath + "/oauth2/token";
    }

    /**
     * 登录并获取令牌（整合流程）
     * 前端只需调用这一个接口，即可完成认证并获取令牌
     */
    @PostMapping("/login")
    public ResponseEntity<Map<String, Object>> loginAndGetToken(@RequestBody LoginParam loginRequest) {
        Map<String, Object> result = new HashMap<>();
    
        try {
            // 1. 验证用户身份（用户名密码）
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginRequest.getUserName(),
                            loginRequest.getPassword()
                    )
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 2. 调用OAuth2令牌端点获取令牌
            TokenResponse tokenResponse = getTokenFromAuthorizationServer(
                    loginRequest.getUserName(),
                    loginRequest.getPassword()
            );

            // 3. 返回成功结果（包含令牌信息）
            result.put("code", 200);
            result.put("msg", "登录成功");
            result.put("data", tokenResponse);
            return ResponseEntity.ok(result);

        } catch (Exception e) {
            result.put("code", 401);
            result.put("msg", "登录失败：" + e.getMessage());
            return ResponseEntity.status(401).body(result);
        }
    }

    /**
     * 刷新令牌
     */
    @PostMapping("/refresh-token")
    public ResponseEntity<Map<String, Object>> refreshToken(@RequestBody Map<String, String> request) {
        String refreshToken = request.get("refreshToken");
        if (refreshToken == null || refreshToken.isEmpty()) {
            return ResponseEntity.badRequest().body(Map.of("code", 400, "msg", "refreshToken不能为空"));
        }

        try {
            // 调用令牌端点刷新令牌
            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            params.add("grant_type", "refresh_token");
            params.add("refresh_token", refreshToken);
            params.add("scope", oauth2Processor.getScopes().get(0));

            TokenResponse tokenResponse = exchangeToken(params);

            Map<String, Object> result = new HashMap<>();
            result.put("code", 200);
            result.put("data", tokenResponse);
            return ResponseEntity.ok(result);

        } catch (Exception e) {
            return ResponseEntity.status(401).body(Map.of("code", 401, "msg", "刷新令牌失败：" + e.getMessage()));
        }
    }

    /**
     * 调用OAuth2授权服务器的令牌端点获取令牌
     */
    private TokenResponse getTokenFromAuthorizationServer(String username, String password) {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        // 使用密码模式
        params.add("grant_type", "password");
        params.add("username", username);
        params.add("password", password);
        params.add("scope", oauth2Processor.getScopes().get(0));
        params.add("client_id", oauth2Processor.getClientId());
        params.add("client_secret", oauth2Processor.getClientSecret());

        return exchangeToken(params);
    }

    /**
     * 通用的令牌交换方法（复用逻辑）
     */
    private TokenResponse exchangeToken(MultiValueMap<String, String> params) {
        // 设置请求头（包含客户端认证信息）
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        String credentials = oauth2Processor.getClientId() + ":" + oauth2Processor.getClientSecret();
        String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes());
        headers.set("Authorization", "Basic " + encodedCredentials);

        // 发送请求获取令牌
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
        ResponseEntity<TokenResponse> response = restTemplate.postForEntity(getTokenEndpoint(), request, TokenResponse.class);

        if (!response.getStatusCode().is2xxSuccessful()) {
            throw new RuntimeException("获取令牌失败：" + response.getStatusCode());
        }

        // 设置令牌颁发时间
        TokenResponse tokenResponse = response.getBody();
        if (tokenResponse != null) {
            tokenResponse.setIssuedAt(Instant.now());
        }

        return tokenResponse;
    }
}
